#include "FdCtx.h"

namespace sylar
{
	FdCtx::FdCtx(int fd) : m_isInit(false), m_isClosed(false), m_isSocket(false), m_sysNonblock(false)
		,m_userNonblock(false), m_fd(fd), m_recvTimeout(-1), m_sendTimeout(-1)
	{
		init();
	}

	FdCtx::~FdCtx()
	{
	}

	bool FdCtx::init()
	{
		if (m_isInit)
		{
			return true;
		}

		struct stat fd_stat;
		if (fstat(m_fd, &fd_stat) == -1)
		{
			m_isInit = false;
			m_isSocket = false;
		}
		else
		{
			m_isInit = true;
			m_isSocket = S_ISSOCK(fd_stat.st_mode);
		}

		if (m_isSocket)
		{
			int flag = fcntl_f(m_fd, F_GETFL, 0);
			if (!(flag & O_NONBLOCK))
			{
				fcntl_f(m_fd, F_SETFL, flag | O_NONBLOCK);
			}
			m_sysNonblock = true;
		}
		else
		{
			m_sysNonblock = false;
		}

		m_userNonblock = false;
		m_isClosed = false;

		return m_isInit;
	}

	bool FdCtx::close()
	{
		return m_isClosed = true;
	}

	void FdCtx::setTimerout(int type, uint64_t v)
	{
		if (type == SO_RCVTIMEO)
		{
			 m_recvTimeout=v;
		}
		else
		{
			m_sendTimeout = v;
		}
	}

	uint64_t FdCtx::getTimerout(int type)
	{

		if (type == SO_RCVTIMEO)
		{
			return m_recvTimeout;
		}
		else
		{
			return m_sendTimeout;
		}
	}



	FdManager::FdManager()
	{
		m_datas.resize(64);
	}

	FdManager::~FdManager()
	{
		RWMutexType::WriteLock wlock(m_mutex);
		for (auto i : m_datas)
		{
			i.reset();
		}
	}

	FdCtx::ptr FdManager::get(int fd, bool auto_create)
	{
		RWMutexType::ReadLock rlock(m_mutex);
		bool isSize = false;
		if (m_datas.size() <= (std::size_t)fd)
		{
			if (auto_create == false)
			{
				return nullptr;
			}
			isSize = true;
		}
		else
		{
			if (m_datas[fd] || !auto_create)
			{
				return m_datas[fd];
			}
		}
	
		rlock.unlock();

		RWMutexType::WriteLock wlock(m_mutex);
		if (isSize)
		{
			m_datas.resize((std::size_t)fd * 1.5);
		}
		FdCtx::ptr ctx(new FdCtx(fd));
		m_datas[fd] = ctx;
		return ctx;
			
	}

	void FdManager::del(int fd)
	{
		RWMutexType::WriteLock lock(m_mutex);
		if (m_datas.size() > fd)
		{
			m_datas.at(fd).reset();
		}
		
	}

}

